home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1996 #14 / Monster Media No. 14 (April 1996) (Monster Media, Inc.).ISO / prog_pas / tsfaqp29.zip / FAQPAS.TXT next >
Internet Message Format  |  1996-01-01  |  79KB

  1. From ts@uwasa.fi Mon Jan 1 00:00:00 1996
  2. Subject: FAQPAS.TXT contents
  3.  
  4.                              Copyright (c) 1993-1996 by Timo Salmi
  5.                                                All rights reserved
  6.  
  7. FAQPAS.TXT Frequently (and not so frequently) asked Turbo Pascal
  8. questions with Timo's answers. The items are in no particular order.
  9.  
  10. You are free to quote brief passages from this file provided you
  11. clearly indicate the source with a proper acknowledgment.
  12.  
  13. Comments and corrections are solicited. But if you wish to have
  14. individual Turbo Pascal consultation, please post your questions to
  15. a suitable Usenet newsgroup like news:comp.lang.pascal.borland. It
  16. is much more efficient than asking me by email. I'd like to help,
  17. but I am very pressed for time. I prefer to pick the questions I
  18. answer from the Usenet news. Thus I can answer publicly at one go if
  19. I happen to have an answer. Besides, newsgroups have a number of
  20. readers who might know a better or an alternative answer. Don't be
  21. discouraged, though, if you get a reply like this from me. I am
  22. always glad to hear from fellow Turbo Pascal users.
  23.  
  24. If you are an experienced Turbo Pascal programmer with Turbo Pascal
  25. material you would like to circulate publicly world-wide, you are
  26. welcome to submit your material to the Garbo MS-DOS archives at the
  27. University of Vaasa. To do that you *FIRST* must *CAREFULLY* read
  28. the uploading instructions and the formal requirements in the file
  29. ftp://garbo.uwasa.fi/pc/UPLOAD.INF. You are also welcome to contact
  30. me by email for these instructions if you are not familiar with
  31. downloading them from the Garbo archives.
  32.  
  33. ....................................................................
  34. Prof. Timo Salmi   Co-moderator of news:comp.archives.msdos.announce
  35. Moderating at ftp:// & http://garbo.uwasa.fi archives  193.166.120.5
  36. Department of Accounting and Business Finance  ; University of Vaasa
  37. ts@uwasa.fi http://uwasa.fi/~ts BBS 961-3170972; FIN-65101,  Finland
  38.  
  39. --------------------------------------------------------------------
  40.  1) How do I disable or capture the break key in Turbo Pascal?
  41.  2) How do I get a printed documentation of my students' TP runs?
  42.  3) What is the code for the weekday of a given date?
  43.  4) Need a program to format Turbo Pascal source code consistently
  44.  5) Can someone give me advice for writing a tsr program?
  45.  6) Why can't I read / write the com ports?
  46.  7) What are interrupts and how to use them in Turbo Pascal?
  47.  8) Should I upgrade my Turbo Pascal version?
  48.  9) How do I execute an MS-DOS command from within a TP program?
  49. 10) How is millisecond timing done?
  50. 11) How can I customize the text characters to my own liking?
  51. 12) How to find the files in a directory and subdirectories?
  52. 13) I need a power function but there is none in Turbo Pascal.
  53. 14) How can I create arrays that are larger than 64 kilobytes?
  54. 15) How can I test that the printer is ready?
  55. 16) How can I clear the keyboard type-ahead buffer?
  56. 17) How can I utilize expanded memory (EMS) in my programs?
  57. 18) How can I obtain the entire command line?
  58. 19) How do I redirect text from printer to file in my TP program?
  59. 20) Turbo Pascal is for wimps. Use standard Pascal or C instead?
  60. 21) How do I turn the cursor off?
  61. 22) How to find all roots of a polynomial?
  62. 23) What is all this talk about "Pascal homework on the net"?
  63. 24) How can I link graphics drivers directly into my executable?
  64. 25) How can I trap a runtime error?
  65. 26) How to get ansi control codes working in Turbo Pascal writes?
  66. 27) How to evaluate a function given as a string to the program?
  67. 28) How does one detect whether input (or output) is redirected?
  68. 29) How does one set the 43/50 line text mode?
  69. 30) How can I assign a value to an environment variable in TP?
  70. --------------------------------------------------------------------
  71.  
  72. Unless otherwise stated the answers cover versions 4.0, 5.0, 5.5,
  73. 6.0 and 7.0 (real mode). The Q&As are not for Turbo Pascal version 3
  74. or earlier. Objects, TVision, Windows, Delphi, etc are not covered.
  75. (I do not use them myself.)
  76. --------------------------------------------------------------------
  77.  
  78. From ts@uwasa.fi Mon Jan 1 00:00:01 1996
  79. Subject: Disabling or capturing the break key
  80.  
  81. 1. *****
  82.  Q: I don't want the Break key to be able to interrupt my TP
  83. programs. How is this done?
  84.  Q2: I want to be able to capture the Break key in my TP program.
  85. How is this done?
  86.  Q3: How do I detect if a certain key has been pressed? (Often, how
  87. do I detect, for example, if the CursorUp key has been pressed?)
  88.  Q4: How do I detect if a cursor key or a function key has been
  89. pressed?
  90.  
  91.  A: This set of frequently asked questions is basically a case of
  92. RTFM (read the f*ing manual). But this feature is, admittedly, not
  93. very prominently displayed in the Turbo Pascal reference. (As a
  94. general rule we should not use the newsgroups as a replacement for
  95. our possibly missing manuals, but enough of this line.)
  96.    I'll only explain Q and Q2. The other two, Q3 and Q4 should be
  97. evident from the example code.
  98.    There is a CheckBreak variable in the Crt unit, which is true by
  99. default. To turn it off use
  100.      uses Crt;
  101.      :
  102.      CheckBreak := false;
  103.      :
  104. Besides turning off break checking this enables you to capture the
  105. pressing of the break key as you would capture pressing ctrl-c. In
  106. other words you can use e.g.
  107.      :
  108.   procedure TEST;
  109.   var key : char;
  110.   begin
  111.     repeat
  112.       if KeyPressed then
  113.         begin
  114.           key := ReadKey;
  115.           case key of
  116.              #0 : begin
  117.                     key := ReadKey;
  118.                     case key of
  119.                       #59 : write ('F1 ');
  120.                       #72 : write ('CursUp ');   { Deteting these  }
  121.                       #75 : write ('CursLf ');   { is often asked! }
  122.                       #77 : write ('CursRg ');
  123.                       #80 : write ('CursDn ');
  124.                       else write ('0 ', ord(key), ' ');
  125.                     end; {case}
  126.                   end;
  127.              #3 : begin    {ctrl-c or break}
  128.                     writeln ('Break');
  129.                     halt(1);
  130.                   end;     { Terminate the program, or whatever }
  131.             #27 : begin
  132.                     write ('<esc> ');
  133.                     exit;  { Exit test, continue program }
  134.                   end;
  135.             else write (key, ' ');
  136.           end; {case}
  137.         end; {if}
  138.     until false;
  139.   end;  (* test *)
  140.      :
  141. IMPORTANT: Don't test the ctrl-break feature just from within the TP
  142. IDE, because it has ctlr-break handler ("interceptor") of its own
  143. and may confuse you into thinking that ctrl-break cannot be
  144. circumvented by the method given above.
  145.   The above example has a double purpose. It also shows the
  146. rudiments how you can detect if a certain key has been pressed. This
  147. enables you to give input without echoing it to the screen, which is
  148. a later FAQ in this collection.
  149.   This is, however, not all there can be to break checking, since
  150. the capturing is possible only at input time. It is also possible to
  151. write a break handler to interrupt a TP program at any time. For
  152. more details see Ohlsen & Stoker, Turbo Pascal Advanced Techniques,
  153. Chapter 7. (For the bibliography, see FAQPASB.TXT in this same FAQ
  154. collection).
  155.  
  156.  A2: This frequent question also elicits one of the most frequent
  157. false answers. It is often suggested erroneously that the relevant
  158. code would be
  159.   uses dos;
  160.   SetCBreak(false);
  161. This is not so. It confuses MS-DOS and TP break checking with each
  162. other. SetCBreak(false) will _*NOT*_ disable the Ctrl-Break key for
  163. your Turbo Pascal program. What it does is "Sets the state of
  164. Ctrl-Break checking in DOS". SetCBreak sets the state of Ctrl+Break
  165. checking in DOS. When off (False), DOS only checks for Ctrl+Break
  166. during I/O to console, printer, or communication devices. When on
  167. (True), checks are made at every system call."
  168.    This item goes to shows how important it is carefully to check
  169. one's code and facts before claiming something.
  170.  
  171.  A3: Using the "CheckBreak := false;" method is not the only
  172. alternative, however. Here is an example code for disabling
  173. Ctrl-Break and Ctrl-C with interrupts
  174.   uses Dos;
  175.   var OldIntr1B : pointer;  { Ctrl-Break address }
  176.       OldIntr23 : pointer;  { Ctrl-C interrupt handler }
  177.       answer    : string;   { For readln test }
  178.   {$F+}
  179.   procedure NewIntr1B (flags,cs,ip,ax,bx,cx,dx,si,di,ds,es,bp : word);
  180.             Interrupt;
  181.   {$F-} begin end;
  182.   {$F+}
  183.   procedure NewIntr23 (flags,cs,ip,ax,bx,cx,dx,si,di,ds,es,bp : word);
  184.             Interrupt;
  185.   {$F-} begin end;
  186.   begin
  187.     GetIntVec ($1B, OldIntr1B);
  188.     SetIntVec ($1B, @NewIntr1B);   { Disable Ctrl-Break }
  189.     GetIntVec ($23, OldIntr23);
  190.     SetIntVec ($23, @NewIntr23);   { Disable Ctrl-C }
  191.     writeln ('Try breaking, disabled');
  192.     readln (answer);
  193.     SetIntVec ($1B, OldIntr1B);    { Enable Ctrl-Break }
  194.     SetIntVec ($23, OldIntr23);    { Enable Ctrl-C }
  195.     writeln ('Try breaking, enabled');
  196.     readln (answer);
  197.     writeln ('Done');
  198.   end.
  199. --------------------------------------------------------------------
  200.  
  201. From ts@uwasa.fi Mon Jan 1 00:00:02 1996
  202. Subject: Directing output also to printer
  203.  
  204. 2. *****
  205.  Q: I want to have a printed documentation of my students' Turbo
  206. Pascal program exercises. How is all input and output directed also
  207. to the printer?
  208.  
  209.  A1: Use a screen capturing program to put everything that comes
  210. onto the screen into a file, and print the file. See FAQPROGS.TXT in
  211. ftp://garbo.uwasa.fi/pc/ts/tsfaqn43.zip (or whatever version number
  212. is the current) for more about these programs. Available by
  213. anonymous FTP or mail server from garbo.uwasa.fi.
  214.  
  215.  A2: See the code in TSPAS.NWS (item: Redirecting writes to the
  216. printer) in the ftp://garbo.uwasa.fi/pc/ts/tspa3470.zip (or whatever
  217. is the current version number) Turbo Pascal units package (70 = 40,
  218. 50, 55, 60, or 70 depending on your TP version). Alternatively use
  219. USECON and USEPRN routines in the TSUNTG unit of the same package.
  220.  
  221.      +------------------------------------------+
  222.      ! To get these and other packages given as !
  223.      !   /dir/subdir/name                       !
  224.      ! see the instructions in PD2ANS.TXT       !
  225.      +------------------------------------------+
  226.  
  227.  A3: But the really elegant solution to the problem of getting a
  228. logfile (or a printed list) of a Turbo Pascal run is to rewrite the
  229. write(ln) and read(ln) device driver functions. In itself writing
  230. such driver redirections is very advanced Turbo Pascal programming,
  231. but when the programming has once been done, the system is extremely
  232. easy to use as many times as you like. It goes like this. The driver
  233. redirections are programmed into a unit (say, tpulog or tpuprn). All
  234. that is needed after that is to include the following uses statement
  235. into the program (the target program) which has to be logged:
  236.       uses TPULOG;    ( or )    uses TPUPRN;
  237. This is all there is to it. Just adding one simple line to the
  238. target program. (If you call any other units, "uses tpulog" must
  239. come AFTER the system units (e.g. Dos), but BEFORE any which you may
  240. define yourself!)
  241.    The reason that I have named two units here instead of just one
  242. in the above example is that the preferred log for the target
  243. program may be a logfile or the printer. The better solution of
  244. these two is to use the logfile option, and then print it. The
  245. reason is simple. If the target program itself prints something,
  246. your printout will look confused.
  247.    The logging also has obvious limitations. It works for standard
  248. input and output (read(ln) and write(ln)) only. 1) It does not
  249. support graphics, in other words it is for the textmode. 2) It does
  250. not support direct (Crt) screen writes. 3) And, naturally it only
  251. shows the input and output that comes to the screen. Not any other
  252. input or output, such as from or to a file. 4) Furthermore, you are
  253. not allowed to reassign input or output. Statements like assign
  254. (output, '') will result in a crash, because the rewritten output
  255. device redirections are invalidated by such statements. 5) The
  256. device on the default drive must not be write protected, since else
  257. the logfile cannot be written to it. 6) It does not work for Turbo
  258. Pascal 4.0. Despite these restrictions, the method is perfectly
  259. suited for logging students' Turbo Pascal escapades.
  260.    It is advisable first to test and run your target program without
  261. "tpulog", so that if you get any strange errors you'll know whether
  262. they are caused by the logging.
  263.    Where to get such a unit. The code can be found in Michael
  264. Tischer (1990), Turbo Pascal Internals, Abacus, Section 4.2. Next a
  265. few of my own tips on this unit Tischer calls Prot. 1) The code is
  266. in incorrect order. The code that is listed on pages 142 - 145 goes
  267. between pages 139 and 140. 2) You can change the logfile name (const
  268. prot_name) to lpt1 for a printed list of the target program run. In
  269. that case it is advisable to include a test for the online status of
  270. the printer within Tischer's unit. 3) I see no reason why the two
  271. lines in Tischer's interface section couldn't be transferred to the
  272. implementation section. Why have any global definitions?  But all in
  273. all, it works like magic!
  274.  
  275.  A4: From: abcscnuk@csunb.csun.edu (Naoto Kimura (ACM))
  276. Subject: Re: Printing a log of students' exercises revisited
  277. To: ts@uwasa.fi
  278. Date: Fri, 2 Nov 90 20:52:03 pdt
  279. [Reproduced with Naoto's kind permission]
  280. By the way, several months ago, I had submitted a file (nktools.zip)
  281. file on SimTel that contains sources to a unit (LOGGER), which
  282. allows logging of I/O going through the standard input and output
  283. files, while still being able to use the program interactively.  I
  284. believe that I also submitted a copy to your site.  It was something
  285. I put together for use by students here at California State
  286. University at Northridge.  The source works equally well in all
  287. presently available versions of Turbo Pascal.
  288. The only requirements are that
  289.  * you place it as one of the last entries in the USES clause.  If
  290.    there is anything that redirects the standard input and output
  291.    file variables, you should put that unit before my unit in the
  292.    USES clause, so that it can see the I/O stream.
  293.  * Don't use the GotoXY and similar screen display control
  294.    procedures in the Crt unit and expect it to come out the same way
  295.    you had it on the display.  Since all my unit does is just
  296.    capture the I/O stream to send it through the normal channels and
  297.    also to the log file, all screen control information is not sent
  298.    to the log file.
  299.  * All I/O you want logged should go through the standard input and
  300.    output file variables.
  301.  * Don't close the standard input and output file variables, because
  302.    it will cause problems.  Basically, as far as I have checked, it
  303.    just causes the logging to stop at that point.
  304. --------------------------------------------------------------------
  305.  
  306. From ts@uwasa.fi Mon Jan 1 00:00:03 1996
  307. Subject: Code to give the weekday of a date
  308.  
  309. 3. *****
  310.  Q: I want code that gives the weekday of the given date.
  311.  
  312.  A1: There is a WKDAYFN function in my Turbo Pascal units collection
  313. ftp://garbo.uwasa.fi/pc/ts/tspa3470.zip (or whatever version number
  314. is the latest, and where 70 is 40 50 55 60 and 70) Turbo Pascal
  315. units collection to give the modern weekday based on Zeller's
  316. congruence. Available by anonymous FTP or mail server from
  317. garbo.uwasa.fi. Also you can find a more extensive Julian and
  318. Gregorian weekday algorithm with source code in Dr.Dobb's Journal,
  319. June 1989, p. 148. Furthermore Press & Flannery & al (1986),
  320. Numerical Recipes, Cambridge University Press, present a weekday
  321. code. The Numerical Recipes codes are available as
  322. ftp://garbo.uwasa.fi/pc/turbopas/nrpas13.zip (big, 404k!).
  323.  
  324.  A2: Some will recommend the following kludge. Store the current
  325. date, change it, and let MS-DOS get you the weekday. Don't use it!
  326. It is a bad suggestion. On top of being sloppy programming, there
  327. are several snags.  The trick works only for years 1980-2079. A
  328. crash the program may leave the clock at a wrong date. And even if
  329. multitasking is rare, in a multitasking environment havoc may result
  330. for the other tasks. And you may have a TSR that requires the
  331. correct date, etc.
  332. --------------------------------------------------------------------
  333.  
  334. From ts@uwasa.fi Mon Jan 1 00:00:04 1996
  335. Subject: Pretty printers (or uniform code)
  336.  
  337. 4. *****
  338.  Q: Where can I find a program that formats my (or my students')
  339. Turbo Pascal code in a consistent matter.
  340.  
  341.  A: What you are asking for is often called "a pretty printer".
  342. TurboPower Software's (the usual disclaimer applies) commercial
  343. Turbo Analyst has a facility for this with many options. There are
  344. also PD and shareware pretty printers, such as
  345.  :
  346.  16830 Nov 28 1989 ftp://garbo.uwasa.fi/pc/turbopas/ppdk50.zip
  347.  ppdk50.zip Pascal Prettypringting Program, tweak, D.Kirschbaum
  348.  :
  349.  10015 Mar 29 1991 ftp://garbo.uwasa.fi/pc/turbopas/ppp.zip
  350.  ppp.zip Pretty Print Pascal, with Turbo Pascal 5+ source, M.Bless
  351.  :
  352.  38021 Nov 5 1994 ftp://garbo.uwasa.fi/pc/turbopas/bp7sb104.zip
  353.  bp7sb104.zip Borland and TP Source Beautifier, crippleware, J.Ferincz
  354.  :
  355.  25100 Jul 4 1992 ftp://garbo.uwasa.fi/pc/turbopas/epb232.zip
  356.  epb232.zip Ed's Pascal Beautifier, E.Lee
  357.  :
  358. and others at garbo.uwasa.fi available by anonymous FTP or mail
  359. server. See ftp://garbo.uwasa.fi/pc/INDEX.ZIP for the list of the
  360. files.
  361. --------------------------------------------------------------------
  362.  
  363. From ts@uwasa.fi Mon Jan 1 00:00:05 1996
  364. Subject: How to write TSR programs
  365.  
  366. 5. *****
  367.  Q: Can someone give me advice for writing a tsr program?
  368.  
  369.  A: Writing a terminate and stay resident program can be considered
  370. advanced programming and is beyond the scope of an electronic
  371. message with limited space. Instead, here are some references to
  372. Turbo Pascal books and papers which have a coverage of the subject.
  373. Stephen O'Brien, Turbo Pascal, The Complete Reference, Chapter 16;
  374. Stephen O'Brien, Turbo Pascal, Advanced Programmer's Guide, Chapter
  375. 6; Michael Tischer, Turbo Pascal Internals, Chapter 11 (a definite
  376. bible of TP programming!); Michael Tischer (1992), PC Intern System
  377. Programming, Chapter 32; Michael Yester, Using Turbo Pascal, Chapter
  378. 19; Kent Pottebaum, "Creating TSR Programs with Turbo Pascal", Dr.
  379. Dobb's Journal, May 1989 and June 1989; Kris Jamsa, Dos Power User's
  380. Guide, pp. 649-; Edward Mitchell (1993), Borland Pascal Developer's
  381. Guide, Section "Writing TSRs", pp. 370-400, with 778 lines of sample
  382. code.
  383.    Also see example code files like
  384. ftp://garbo.uwasa.fi/pc/turboobj/tsrhelp.zip,
  385. ftp://garbo.uwasa.fi/pc/turbopa45/tess-5.zip,
  386. ftp://garbo.uwasa.fi/pc/turbopa45/tsrunit.zip,
  387. ftp://garbo.uwasa.fi/pc/turbopa7/pptsr10.zip,
  388. ftp://garbo.uwasa.fi/pc/turbopa7/tsrsrc35.zip,
  389. ftp://garbo.uwasa.fi/pc/turbopas/deltsr.zip,
  390. ftp://garbo.uwasa.fi/pc/turbopas/tp4_tsr.zip.
  391.    Furthermore, you should see the TSR.SWG examples in the fine SWAG
  392. (SourceWare Archival Group's) collection of TP sources. Available
  393. from the /pc/turbopas directory at Garbo. For the current references
  394. to the SWAG files see ftp://garbo.uwasa.fi/pc/INDEX.ZIP.
  395. --------------------------------------------------------------------
  396.  
  397. From ts@uwasa.fi Mon Jan 1 00:00:06 1996
  398. Subject: Programming com ports
  399.  
  400. 6. *****
  401.  Q: Why can't I read / write the com ports.
  402.  
  403.  A: Com port programming (most often writing telecommunication
  404. programs) is much much more complicated than simply trying to use
  405.   write (com, whatever);
  406.   read  (com, whatever);
  407. This is a very advanced subject (frankly, beyond me), and the best
  408. way to learn is to try to obtain some code to show you how. One
  409. place to look at is Turbo Pascal text-books (I have a long list of
  410. them at garbo.uwasa.fi archives in my collection of Turbo Pascal
  411. units ftp://garbo.uwasa.fi/pc/ts/tsfaqp3470.zip. There also is an
  412. example by David Rind in ftp://garbo.uwasa.fi/pc/pd2/faquote.zip.
  413. Another source is International FidoNet pascal conference at some
  414. bulletin board near you. The conference has had some very good
  415. discussions in it. (No, I don't have them stored for distribution,
  416. nor any further information.) Some files you might wish to look at:
  417. ftp://garbo.uwasa.fi/pc/turbopas/comm_tp5.zip and comtty30.zip.
  418.    Furthermore, you should see the COMM.SWG examples in the fine
  419. SWAG (SourceWare Archival Group's) collection of TP sources.
  420. Available from the /pc/turbopas directory at Garbo. For the current
  421. references to the SWAG files see ftp://garbo.uwasa.fi/pc/INDEX.ZIP.
  422. --------------------------------------------------------------------
  423.  
  424. From ts@uwasa.fi Mon Jan 1 00:00:07 1996
  425. Subject: Primers to interrupt programming
  426.  
  427. 7. *****
  428.  Q: What are interrupts and how to use them in Turbo Pascal?
  429.  
  430.  A: An interrupt is a signal to the processor from a program, a
  431. hardware device, or the processor itself, to suspend temporarily
  432. what the program is doing, and to perform a routine that is stored
  433. in the operating system. There are 256 such interrupt routines, with
  434. many subservices stored in memory at locations, which are given in
  435. the so called interrupt table. Turbo Pascal (somewhat like C) has a
  436. special keyword Intr, and a predefined variable registers (in the
  437. Dos unit) to access these interrupt routines. One way of looking at
  438. them is as Turbo Pascal (complicated lowlevel) subroutines that are
  439. already there ready for you to call.
  440.    A detailed description of interrupt routines is way beyond a
  441. single message with limited space. Instead, I shall give a simple
  442. example, and good references to the subject. (For a somewhat more
  443. comprehensive description of what an interrupt is, see INTERRUP.PRI
  444. in Ralf Brown's ftp://garbo.uwasa.fi/pc/programming/inter48b.zip.)
  445.      :
  446.      uses Dos;
  447.      (* This procedure turns on the border color for CGA and VGA *)
  448.      procedure BORDER (color : byte);
  449.      var regs : registers;  (* Predeclared in the Dos unit *)
  450.      begin
  451.        FillChar (regs, SizeOf(regs), 0);  (* A precaution *)
  452.        regs.ax := $0B00;    (* Service number *)
  453.        regs.bh := $00;      (* Subservice number *)
  454.        regs.bl := color;
  455.        Intr ($10, regs);    (* ROM BIOS video driver interrupt *)
  456.      end;  (* border *)
  457.    If you are new the subject and / or want ideas on the most useful
  458. interrupts in Turbo Pascal programming, Ben Ezzel (1989),
  459. Programming the IBM User Interface Using Turbo Pascal, is definitely
  460. the best reference to look at. There are also many other good
  461. references for a novice interrupt user, such as Jamsa & Nameroff,
  462. Turbo Pascal Programmer's Library.
  463.    If you are a more advanced interrupt user you'll find the
  464. following references very useful. Michael Tischer (1990), Turbo
  465. Pascal Internals; Norton & Wilton (1988), The New Peter Norton
  466. Programmer's guide to the IBM PC & PS/2; Ray Duncan (1988), Advanced
  467. MS-DOS Programming; Terry Dettmann (1989), Dos Programmer's
  468. Reference, Second edition, Que. Furthermore, there is an impressive
  469. list of interrupts collected and maintained by Ralf Brown. His
  470. extensive ftp://garbo.uwasa.fi:/pc/programming/inter48a.zip,
  471. inter48b.zip, inter48c.zip, inter48d.zip, inter48e.zip and
  472. inter48f.zip (or whatever are the current versions when you read
  473. this) is available by anonymous FTP or mail server from
  474. garbo.uwasa.fi. A definite must for an advanced user. Also see the
  475. reference to Brown's and Kyle's book in the bibliography at the end
  476. of this FAQ. There is also a good hypertext advanced programmer's
  477. quick reference ftp://garbo.uwasa.fi/pc/programming/helppc21.zip
  478. which you might find useful.
  479.    One more point for Turbo Pascal users. When Borland upgraded from
  480. version 3 to 4.0 quite a number of tasks that needed to be done
  481. using interrupts (such as getting the current time) were included as
  482. normal TP routines. This means that while definitely useful,
  483. interrupt programming is now relevant only in advanced Turbo Pascal
  484. programming. Turbo Pascal 5.0 introduced a few more, but you can
  485. find some of the missing TP 4.0 routines in the compatibility unit
  486. in my ftp://garbo.uwasa.fi/pc/ts/tspa3440.zip TP units collection.
  487. --------------------------------------------------------------------
  488.  
  489. From ts@uwasa.fi Mon Jan 1 00:00:08 1996
  490. Subject: Borland's Turbo Pascal upgrades
  491.  
  492. 8. *****
  493.  Q: Should I upgrade my Turbo Pascal version?
  494.  
  495.  A1: Depends on what version you are using, and for what purposes.
  496. If you are using version 3, the answer is a definite yes. There are
  497. so many useful additions in the later version, including the concept
  498. of units, and a great number of new useful keywords. The only reason
  499. that I can think of for using TP 3 is that it makes .com files
  500. (which reside in one memory segment only) instead of .exe files. As
  501. an accounting and business finance teacher and researcher I've been
  502. somewhat surprised to see postings stating that some users still
  503. have to program in TP 3.0 because their employer doesn't want to
  504. take the cost of upgrading. I find this cost argument ridiculous.
  505. How about some consideration for cost effectiveness and
  506. productivity?
  507.    If you are currently using version 4.0, the most important point
  508. in considering upgrading is the integrated debugger in the later
  509. versions. It is really good, and useful if you write much code.
  510. There are some minor considerations, as well. Later versions contain
  511. some useful routines which 4.0 does not. I have programmed many of
  512. them to be available also for 4.0 in my units collection
  513. ftp://garbo.uwasa.fi/pc/ts/tspa3440.zip (or whatever is the latest
  514. when you read this). Furthermore, I find somewhat annoying that the
  515. executables will always end up in the default directory.
  516.    If you are currently using version 5.0 the rational reasons for
  517. upgrading are needing objects, and a better overlay manager. I have
  518. also version 5.5 myself, but switched back to version 5.0 after I
  519. had some problems with its linking of object files. (This is a false
  520. statement from me, since it turned out that I had made a mistake
  521. myself. My thanks are due to bj_stedm@gould2.bristol-poly.ac.uk
  522. (Bruce Stedman) for questioning this item). Anyway, I don't use nor
  523. need OOP objects (don't confuse linking object files and object
  524. oriented programming here). One further point for 5.5. It has a
  525. better help function than 5.0, and a few more procedures and
  526. predefined constants. The TP 5.5 help includes examples, which can
  527. be even pasted into your program. This is handy.
  528.    The real snag in upgrading (waiving the reasonable cost) is the
  529. fact that the units of the different versions are incompatible. If
  530. you have a large library of units (as I do) you will have to
  531. recompile the lot. This is something that has caused a fair amount
  532. of justifiable flak against an otherwise excellent product.
  533.    A tip. Don't throw away your Turbo Pascal version 3.0 manual, if
  534. you have one. It is of use if you resort to the Turbo3 and Graph3
  535. compatibility units. They give you access e.g. to turtle graphics.
  536.    At the time of first writing this Turbo Pascal 6.0 version had
  537. just been announced. I didn't have it yet myself, but I had been
  538. (correctly) informed that its units are not compatible with the
  539. earlier versions. I now have Turbo Pascal 6.0, and I must say that
  540. my reactions have been disappointment and frustration. This is
  541. probably partly (but not entirely) my own fault, since Turbo Pascal
  542. seems to be headed from a common programming language into a full
  543. professional's specialized tool, with many features I don't know how
  544. to utilize. The only advancement from my point of view really is the
  545. multiple file editing, but I have long had alternative programs for
  546. that. If I used assembler (I don't) I am sure that I would find
  547. useful TP 6.0's potential to include assembler code as such instead
  548. of having to use the cumbersome Inline procedure of entering the
  549. assembler code.
  550.    There is also a Windows Turbo Pascal, as the latest addition to
  551. the plethora. Since I don't use Windows at all, I have no further
  552. information on it.
  553.    I think a pattern is emerging here. Rather than being different
  554. versions of the same product, the consecutive Turbo Pascals are
  555. really different products for different purposes. Version 3.0 was a
  556. simple programming language. Version 4.0 extended it into a full
  557. scale programming modular platform. Version 5.0 introduced the
  558. debugger. And there an advanced hobbyist's path ended. Version 5.5
  559. introduced object oriented programming, which I'm sure is important
  560. for the initiated, but personally I just don't need it even if I
  561. write a lot of programs. And with the 6.0 we go completely out of
  562. the realm of conventional programming into Turbo Pascal visions.
  563. And Windows Turbo Pascal is for a different platform, altogether.
  564.    I find the new integrated user interface of TP 6.0 awkward in
  565. comparison to what was used in the 4.0, 5.0, and 5.5 versions. The
  566. IDE of TP leaves less free memory than the previous versions.
  567. Furthermore TP 6.0 IDE performs frequent disk accesses which cause
  568. slowdowns  making it virtually unusable from a floppy. And I
  569. wonder why Borland didn't at once go all the way to Windows, because
  570. that is what 6.0 really is. An intermediate, incomplete step in that
  571. direction. This means that we have a 5th upgrade in line with
  572. incompatible units. This is aggravating even for a TP fan, isn't it?
  573.    For information on Turbo Pascal version 7.0 and Borland email
  574. contact numbers see ftp://garbo.uwasa.fi/pc/turbopa7/bp7-info.zip.
  575. Also see ftp://garbo.uwasa.fi/pc/turbspec/bp7bugs2.zip by Duncan
  576. Murdoch. Turbo Pascal 7.0 or more extensively Borland Pascal 7.0 is
  577. a full professional's tool, and far beyond for example my moderate
  578. programming needs. To list only a few of the features are protected
  579. mode programming, handling of large programs, very fast compiling,
  580. and a daunting amount of material elbowing its away on one's disk
  581. space if one ever has the patience to look through it all. I would
  582. use the word "overwhelming". But for a serious programmer this is an
  583. impressive and a very worthwhile tool. One should not be misled
  584. skipping it because of my comments which were written from a
  585. hobbyist's point of view. As a general trend in programs, the
  586. well-known columnist John C. Dvorak calls this increasing product
  587. complexity trend "featurism" in PC Computing, May 1993. But TP 7.0
  588. (7.01) has some important features also from a hobbyist's point of
  589. view. So much so that I have finally succumbed to 7.01 myself. I
  590. particularly like the color coding of the keywords, and the TPX
  591. version enabling compiling very large programs (utilizing extended
  592. memory). A very welcome addition are the new keywords break and
  593. continue to exit or recycle a for, while or a repeat loop are.
  594. Besides they make using the outcast goto statements virtually
  595. unnecessary.
  596.  
  597.  A2: From: dmurdoch@watstat.waterloo.edu (Duncan Murdoch),
  598. Newsgroups: comp.lang.pascal. Included with Duncan's kind
  599. permission. [Duncan is one of the most knowledgeable and useful
  600. contributors to the comp.lang.pascal UseNet newsgroup (later
  601. replaced by comp.lang.pascal.borland for TP)].
  602.    One other reason:  there's a bug in the code generator for 4.0
  603. and 5.0 that makes it handle the Extended (10 byte) real type
  604. poorly.  The code generated makes very poor use of the 8 element
  605. internal stack on the coprocessor, so that expressions with lots of
  606. operands like
  607.   e1+e2+e3+e4+e5+e6+e7+e8+e9
  608. always fail, if all the e's are of type extended.  (The generated
  609. code pushes each operand onto the stack, then does all the adds.
  610. It's smarter to push and add them one at a time.)
  611.    This makes it a real pain translating numerical routines from
  612. Fortran, especially since constants are taken to be of type
  613. extended.
  614.    The bug was fixed in 5.5.
  615.  
  616.  A3: From: Bengt Oehman (d92bo@efd.lth.se): A difference between
  617. v4.0 and v5.5 is that you can calculate constants in tp55, but not
  618. in 4.0. I see this as a big advantage. For example:
  619.   CONST MaxW = 10;
  620.         MaxH = 20;
  621.         MaxSize = MaxW*MaxH;
  622.         { or }
  623.         MaxX = 100;
  624.         HalfMaxX = MaxX DIV 2;
  625. cannot be compiled with 4.0.
  626. --------------------------------------------------------------------
  627.  
  628. From ts@uwasa.fi Mon Jan 1 00:00:09 1996
  629. Subject: Shelling from a TP program
  630.  
  631. 9. *****
  632.  Q: How do I execute an MS-DOS command from within a TP program?
  633.  
  634.  A: The best way to answer this question is to give an example.
  635.      {$M 2048, 0, 0}   (* <-- Important *)
  636.      program outside;
  637.      uses dos;
  638.      begin
  639.        write ('Directory call from within TP by Timo Salmi');
  640.        SwapVectors;
  641.        Exec (GetEnv('comspec'), '/c dir *.*');  (* Execution *)
  642.        SwapVectors;
  643.        (* Testing for errors is recommended *)
  644.        if DosError <> 0 then
  645.          writeln ('Dos error number ', DosError)
  646.        else
  647.          writeln ('Mission accomplished, exit code ', DosExitCode);
  648.        (* For DosError and DosExitCode details see the TP manual *)
  649.      end.
  650. Alternatively, take a look at execdemo.pas from demos.arc which
  651. should be on the disk accompanying Turbo Pascal.
  652.    What the above Exec does is that it executes the command
  653. processor. The /c specifies that the command interpreter is to
  654. perform the command, and then stop (not halt).
  655.    I have also seen it asked how one can swap the Turbo Pascal
  656. program to the disk when shelling. It is unnecessary to program that
  657. separately because there is an excellent program to do that for you.
  658. It is ftp://garbo.uwasa.fi/pc/sysutil/shrom24b.zip.
  659.    Somewhat surprisingly some users have had difficulties with
  660. redirecting shelled output. It is straight-forward. In the above
  661. code one would use, for example
  662.   Exec (GetEnv('comspec'), '/c dir *.* > tmp');
  663. --------------------------------------------------------------------
  664.  
  665. From ts@uwasa.fi Mon Jan 1 00:00:10 1996
  666. Subject: Millisecond timing
  667.  
  668. 10. *****
  669.  Q: How is millisecond timing done?
  670.  
  671.  A: A difficult task, but the facilities are readily available.
  672. TurboPower Software's commercial Turbo Professional (don't confuse
  673. with Borland's Turbo Professional) has a unit for this. (The usual
  674. disclaimer applies). It is called tptimer and is part of the
  675. ftp://garbo.uwasa.fi/pc/turbopas/bonus507.zip package. This one has
  676. been released to the PD. I have also seen a SimTel upload
  677. announcement of a ztimer11.zip for C and ASM, but I have no further
  678. information on that. ftp://garbo.uwasa.fi/pc/turbopas/qwktimer.zip
  679. is another option. It is not quite as accurate as tptimer.
  680.    To test the tptimer unit in bonus507.zip you can use the
  681. following example code
  682.   uses Crt, tptimer;
  683.   var time1, time2 : longint;
  684.   begin
  685.     InitializeTimer;
  686.     time1 := ReadTimer;
  687.     Delay (1356);    (* Or whatever code you wish to benchmark *)
  688.     time2 := ReadTimer;
  689.     RestoreTimer;
  690.     writeln ('Elapsed = ', ElapsedTime (time1, time2)/1000.0 : 0 : 3);
  691.   end.
  692.    It is quite another question when you really need the millisecond
  693. timing. The most common purpose for millisecond timing is testing
  694. the efficiency of alternative procedures and functions, right? The
  695. way I compare mine is simple. I call the procedures or functions I
  696. want to compare for speed, say, a thousand times in a loop.  And
  697. test this for elapsed time. This way the normal resolution (18.2
  698. cycles per second) of the system clock becomes sufficient. This is
  699. accurate enough for the comparisons.
  700.      var elapsed : real; i : word;
  701.      elapsed := TIMERFN;  (* e.g. from /pc/ts/tspa3455.zip *)
  702.      for i := 1 to 1000 do YOURTEST;  (* Try out the alternatives *)
  703.      elapsed := TIMERFN - elapsed;
  704.      writeln ('Elapsed : ', elapsed : 0 : 2);
  705. Incidentally, if you want to make more elaborate evaluations of the
  706. efficiency of your code, Borland's Turbo Profiler is a useful tool.
  707. (The usual disclaimer naturally applies.)
  708. --------------------------------------------------------------------
  709.  
  710. From ts@uwasa.fi Mon Jan 1 00:00:11 1996
  711. Subject: Text font customizing
  712.  
  713. 11. *****
  714.  Q: How can I customize the text characters to my own liking?
  715.  
  716.  A: As far as I know, text-mode characters are hard-coded, and
  717. cannot be customized at all unless you have an EGA or VGA adapter.
  718. But you can always retrieve the bitmap information for the ascii
  719. characters from your PC.
  720.    The bitmap table for the lower part of the character set (0-127)
  721. starts at memory position $F000 and ends at $FA6E. The upper part is
  722. not at a fixed memory location. The pointer to the memory address of
  723. upper part of the ascii table (provided that graftabl has been
  724. loaded) is at an address $007C. One way of saying this is that the
  725. segment address of the upper part's memory location is at $007E, and
  726. its offset at $007C.
  727.    Going into more details is beyond the scope of this posting. If
  728. you want more information see Michael Tischer (1992), PC Intern
  729. System Programming, "Selecting and Programming Fonts", pp. 197-210.
  730. It also has information on a remotely related task of using sprites
  731. (pp. 305-373), a concept familiar from the days of the Commodore 64
  732. games programming. For another reference to customizing characters
  733. see Kent Porter (1987), Stretching Turbo Pascal, Chapter 12, and
  734. Kent Porter & Mike Floyd (1990), Stretching Turbo Pascal. Version
  735. 5.5. Revised Edition. Brady, Chapter 11.
  736.    If you are interested in a demonstration of utilizing the
  737. bitmapped character information (no source code available), take a
  738. look at the demo in the garbo.uwasa.fi anonymous FTP archives file
  739. ftp://garbo.uwasa.fi/pc/ts/tsdemo16.zip (or whatever version number
  740. is current).
  741.    Turbo Pascal also supports what is called stroked fonts (the
  742. .chr) files which draw characters instead of bitmapping them. The
  743. user should be able to write one's own .chr definitions, but I have
  744. no experience nor information on how this can be done.
  745.    There is something called bgikit10.zip which has facilities for
  746. making fonts and adding graphics drivers. The problem is that I
  747. cannot make it publicly available, since I think that it is not PD.
  748. I am still missing the information. Unfortunately, it is not even
  749. the only case where I encountered the fact that Borland does not
  750. seem at all interested in the UseNet users' queries about the status
  751. and distributability of their material.
  752.    (From Leonard Erickson Leonard.Erickson@f51.n105.z1.fidonet.org
  753. Well, you can *also* do it if you have a Hercules Graphics Card Plus
  754. or Hercules InColor card (as far as I know, the only cards that
  755. implemented Hercules RamFont 'standard'). And you can modify the
  756. upper 128 characters on a CGA card. BTW, the RamFont cards are
  757. *nice* pity it appeared too late to become a standard. It's a *lot*
  758. more flexible than EGA/VGA fonts (I can have several *dozen* fonts
  759. resident).)
  760. --------------------------------------------------------------------
  761.  
  762. From ts@uwasa.fi Mon Jan 1 00:00:12 1996
  763. Subject: Finding files in TP
  764.  
  765. 12. *****
  766.  Q: How to find the files in a directory AND subdirectories?
  767.  
  768.  A: Writing a program that goes through the files of the directory,
  769. and all the subdirectories below it, is based on Turbo Pascal's file
  770. finding commands and recursion. This is universal whether you are
  771. writing, for example, a directory listing program, or a program that
  772. deletes, say, all the .bak files, or some other similar task.
  773.    To find (for listing or other purposes) the files in a directory
  774. you need above all the FindFirst and FindNext keywords, and testing
  775. the predefined file attributes. You make these a procedure, and call
  776. it recursively. If you want good examples with source code, please
  777. see PC World, April 1989, p. 154; Kent Porter & Mike Floyd (1990),
  778. Stretching Turbo Pascal. Version 5.5. Revised Edition, Chapter 23;
  779. Michael Yester (1989), Using Turbo Pascal, p. 437; Michael Tischer
  780. (1992), PC Intern System Programming, pp. 796-798.
  781.    The simple (non-recursive) example listing all the read-only
  782. files in the current directory shows the rudiments of the principle
  783. of Using FindFirst, FindNext, and the file attributes, because some
  784. users find it hard to use these keywords. Also see the code in the
  785. item "How to establish if a name refers to a directory or not?" of
  786. this same FAQ collection you are now reading.
  787.     uses Dos;
  788.     var FileInfo : SearchRec;
  789.     begin
  790.       FindFirst ('*.*', AnyFile, FileInfo);
  791.       while DosError = 0 do
  792.         begin
  793.           if (FileInfo.Attr and ReadOnly) > 0 then
  794.             writeln (FileInfo.Name);
  795.           FindNext (FileInfo);
  796.         end;
  797.     end.  (* test *)
  798.  
  799.  A2: While we are on the subject related to FindFirst and FindNext,
  800. here are two useful examples:
  801.  
  802. (* Number of files in a directory (not counting directories) *)
  803. function DFILESFN (dirName : string) : word;
  804. var nberOfFiles  : word;
  805.     FileInfo     : searchRec;
  806. begin
  807.   if dirName[Length(dirName)] <> '\' then dirName := dirName + '\';
  808.   dirName := dirName + '*.*';
  809.   {}
  810.   nberOfFiles := 0;
  811.   FindFirst (dirName, AnyFile, FileInfo);
  812.   while DosError = 0 do
  813.     begin
  814.       if ((FileInfo.Attr and VolumeId) = 0) then
  815.         if (FileInfo.Attr and Directory) = 0 then
  816.           Inc (nberOfFiles);
  817.       FindNext (FileInfo);
  818.     end; {while}
  819.   dfilesfn := nberOfFiles;
  820. end;  (* dfilesfn *)
  821.  
  822. (* Number of immediate subdirectories in a directory *)
  823. function DDIRSFN (dirName : string) : word;
  824. var nberOfDirs : word;
  825.     FileInfo    : searchRec;
  826. begin
  827.   if dirName[Length(dirName)] <> '\' then dirName := dirName + '\';
  828.   dirName := dirName + '*.*';
  829.   {}
  830.   nberOfDirs:= 0;
  831.   FindFirst (dirName, AnyFile, FileInfo);
  832.   while DosError = 0 do
  833.     begin
  834.       if ((FileInfo.Attr and VolumeId) = 0) then
  835.         if (FileInfo.Attr and Directory) > 0 then
  836.           if (FileInfo.Name <> '.') and (FileInfo.Name <> '..') then
  837.             Inc (nberOfDirs);
  838.       FindNext (FileInfo);
  839.     end; {while}
  840.   ddirsfn := nberOfDirs;
  841. end;  (* ddirsfn *)
  842. --------------------------------------------------------------------
  843.  
  844. From ts@uwasa.fi Mon Jan 1 00:00:13 1996
  845. Subject: A generic power function code for TP
  846.  
  847. 13. *****
  848.  Q: I need a power function but there is none in Turbo Pascal.
  849.  
  850.  A: Pascals do not have an inbuilt power function. You have to write
  851. one yourself. The common, but non-general method is defining
  852.    function POWERFN (number, exponent : real) : real;
  853.      begin
  854.        powerfn := Exp(exponent*Ln(number));
  855.      end;
  856. To make it general use:
  857.    (* Generalized power function by Prof. Timo Salmi *)
  858.    function GENPOWFN (number, exponent : real) : real;
  859.    begin
  860.      if (exponent = 0.0) then
  861.        genpowfn := 1.0
  862.      else if number = 0.0 then
  863.        genpowfn := 0.0
  864.      else if abs(exponent*Ln(abs(number))) > 87.498 then
  865.        begin writeln ('Overflow in GENPOWFN expression'); halt; end
  866.      else if number > 0.0 then
  867.        genpowfn := Exp(exponent*Ln(number))
  868.      else if (number < 0.0) and (Frac(exponent) = 0.0) then
  869.        if Odd(Round(exponent)) then
  870.          genpowfn := -GENPOWFN (-number, exponent)
  871.        else
  872.          genpowfn :=  GENPOWFN (-number, exponent)
  873.      else
  874.        begin writeln ('Invalid GENPOWFN expression'); halt; end;
  875.    end;  (* genpowfn *)
  876. On the lighter side of things an extract from an answer of mine in
  877. the late comp.lang.pascal UseNet newsgroup:
  878.  >anyone point out why X**Y is not allowed in Turbo Pascal?
  879.    The situation in TP is a left-over from standard
  880.    Pascal. You'll recall that Pascal was originally
  881.    devised for teaching programming, not for
  882.    something as silly and frivolous as actually
  883.    writing programs.  :-)
  884. --------------------------------------------------------------------
  885.  
  886. From ts@uwasa.fi Mon Jan 1 00:00:14 1996
  887. Subject: Arrays > 64K
  888.  
  889. 14. *****
  890.  Q: How can I create arrays that are larger than 64 kilobytes?
  891.  
  892.  A: Turbo Pascal does not directly support the so-called huge arrays
  893. but you can get by this problem with a clever use of pointers as
  894. presented in Kent Porter, "Handling Huge Arrays", Dr.Dobb's Journal,
  895. March 1988. In this method you point to an element of a two
  896. dimensional array using a^[row].col^[column]. The idea involves too
  897. much code and explanation to be repeated here, so you'll have to see
  898. the original reference. But I know from my own experience, that the
  899. code works like magic. (The code is available from garbo.uwasa.fi
  900. archives as ftp://garbo.uwasa.fi/pc/turbopas/ddj8803.zip). Kent
  901. Porter, "Huge Arrays Revisited", Dr.Dobb's Journal, October 1988,
  902. presents the extension of the idea to huge virtual arrays. (Virtual
  903. arrays mean arrays that utilize disk space).
  904.    Another possibility is using TurboPower Software's (the usual
  905. disclaimer applies) commercial Turbo Professional (don't confuse
  906. with Borland's Turbo Professional) package. It has facilities for
  907. huge arrays, but they involve much more overhead than Kent Porter's
  908. excellent method.
  909.  
  910. (* =================================================================
  911.    My code below is based on a UseNet posting in the late
  912.    comp.lang.pascal by Naji Mouawad nmouawad@watmath.waterloo.edu.
  913.    Naji's idea was for a vector, my adaptation is for a
  914.    two-dimensional matrix. The realization of the idea is simpler
  915.    than the one presented by Kent Porter in Dr.Dobb's Journal, March
  916.    1988. (Is something wrong, this is experimental.)
  917.    ================================================================= *)
  918.    {}
  919.    const maxm = 150;
  920.          maxn = 250;
  921.    {}
  922.    type BigVectorType = array [1..maxn] of real;
  923.         BigMatrixType = array [1..maxm] of ^BigVectorType;
  924.    {}
  925.    var BigAPtr : BigMatrixType;
  926.    {}
  927.    (* Create the dynamic variables *)
  928.    procedure MAKEBIG;
  929.    var i          : word;
  930.        heapNeeded : longint;
  931.    begin
  932.      heapNeeded := maxm * maxn * SizeOf(real) + maxm * 4 + 8196;
  933.      if (MaxAvail <= heapNeeded) then
  934.        begin writeln ('Out of memory'); halt; end;
  935.      for i := 1 to maxm do New (BigAPtr[i]);
  936.    end;  (* makebig *)
  937.    {}
  938.    (* Test that it works *)
  939.    procedure TEST;
  940.    var i, j : word;
  941.    begin
  942.      for i := 1 to maxm do
  943.        for j := 1 to maxn do
  944.          BigAPtr[i]^[j] := i * j;
  945.      {}
  946.      writeln (BigAPtr[5]^[7] : 0:0);
  947.      writeln (BigAPtr[maxm]^[maxn] : 0:0);
  948.    end;  (* test *)
  949.    {}
  950.    (* The main program *)
  951.    begin
  952.      writeln ('Big arrays test by Prof. Timo Salmi, Vaasa, Finland');
  953.      writeln;
  954.      MAKEBIG;
  955.      TEST;
  956.    end.
  957. (For a better test of the heap than in MAKEBIG see Swan (1989), pp.
  958. 462-463.)
  959. --------------------------------------------------------------------
  960.  
  961. From ts@uwasa.fi Mon Jan 1 00:00:15 1996
  962. Subject: Testing printer status
  963.  
  964. 15. *****
  965.  Q: How can I test that the printer is ready?
  966.  
  967.  A: Strictly speaking there is no guaranteed way to detect the
  968. printer status on a PC. As Brian Key Brian@fantasia.demon.co.uk
  969. wrote "Any book dealing with the PC BIOS support of a printer will
  970. quickly show you that there is no hardware definition which deals
  971. with the printer power status.  It simply wasn't designed (and I use
  972. the word loosely!) into the IBM hardware specs."
  973.  
  974.    The usually advocated method in Turbo Pascal is to test the
  975. status of regs.ah after a call to interrupt 17 Hex (the parallel
  976. port driver interrupt), service 02:
  977.       regs.dx := PrinterNumber;  (* LPT1 = 0 *)
  978.       regs.ah := $02;            (* var regs : registers, uses DOS *)
  979.       Intr ($17,regs);           (* Interrupt 17 Hex *)
  980.       status := regs.ah          (* var status : byte *)
  981. But this is not a good method since the combinations of the status
  982. bits which indicate a ready state can vary from printer to printer
  983. and PC to PC. If you want a list of the status bits, see e.g. Ray
  984. Duncan (1988), Advanced MS-DOS Programming, p. 587. For an example
  985. of a code using interrupt 17 Hex see Douglas Stivison (1986), Turbo
  986. Pascal Library, pp. 118-120. Also see Michael Yester (1989), Using
  987. Turbo Pascal, pp. 494-495.
  988.    The more generic alternative is to try to write a #13 to the
  989. printer having the i/o checking off, that is, while {$I-} is in
  990. effect, and testing the IOResult. But then you must first alter the
  991. printer retry times default (and restore it afterwards). Else the
  992. method can take up to a minute instead of an immediate response.
  993. Also, you must have set the FileMode for LPT1 appropriately (and
  994. restore it afterwards). Sounds a bit complicated, but you don't have
  995. to do all this yourself. There is a boolean function "LPTONLFN Get
  996. the online status of the first parallel printer" for this purpose in
  997. my ftp://garbo.uwasa.fi/pc/ts/tspa3470.zip (or whatever version
  998. number is the latest) Turbo Pascal units collection available by
  999. anonymous FTP or mail server from garbo.uwasa.fi.
  1000.  
  1001.  A2: One potential, somewhat advanced solution is to use the Device
  1002. Driver Control (IOCTL) information. Here is the code.
  1003.   uses Dos;
  1004.   function PRNSTAFN : boolean;
  1005.   var regs   : registers;
  1006.       handle : ^word;
  1007.       f      : file;
  1008.   begin
  1009.     prnstafn := false;
  1010.     if swap(Dosversion) < $0200 then exit;  { At least MS-DOS 2.0 }
  1011.     Assign (f, 'prn');                 { Printer }
  1012.     Reset (f);
  1013.     FillChar (regs, SizeOf(regs), 0);  { Just to make sure }
  1014.     regs.ah := $44;                    { Function $44 }
  1015.     regs.al := $07;                    { Subfunction $07 }
  1016.     handle  := @f;                     { Establish a file handle }
  1017.     regs.bx := handle^;
  1018.     Msdos (regs);                      { Call interrupt $21 }
  1019.     Close (f);
  1020.     if regs.flags and FCarry <> 0 then exit;  { Is the carry flag set? }
  1021.     if regs.al <> $FF then exit;       { regs.al = $FF signals success}
  1022.     prnstafn := true;
  1023.   end;  (* prnstafn *)
  1024.   {}
  1025.   begin
  1026.     if PRNSTAFN then writeln ('Printer ready')
  1027.       else writeln ('Printer not ready');
  1028.     readln;
  1029.   end.
  1030. --------------------------------------------------------------------
  1031.  
  1032. From ts@uwasa.fi Mon Jan 1 00:00:16 1996
  1033. Subject: Clearing the keyboard buffer
  1034.  
  1035. 16. *****
  1036.  Q: How can I clear the keyboard type-ahead buffer?
  1037.  
  1038.  A: Three methods are usually suggested for solving this problem.
  1039. a) The first is to use something like
  1040.      uses Crt;
  1041.      while KeyPressed do ReadKey;
  1042. This kludge-type method has the disadvantage of requiring the Crt
  1043. unit. Also, in connection with procedures relying on ReadKey for
  1044. input, it may cause havoc on the programs logic.
  1045. b) The second method accesses directly the circular keyboard buffer
  1046.      var head : word absolute $0040:$001A;
  1047.          tail : word absolute $0040:$001C;
  1048.      procedure FLUSHKB; begin head := tail; end;
  1049. For a slightly different formulation of the same method see Michael
  1050. Tischer (1992), PC Intern System Programming, p. 462.
  1051. c) The third method is to call interrupt 21Hex (the MS-DOS
  1052. interrupt) with the ax register set as $0C00. This method has the
  1053. advantage of not being "hard-coded" like the second method, and thus
  1054. should be less prone to incompatibility.
  1055. --------------------------------------------------------------------
  1056.  
  1057. From ts@uwasa.fi Mon Jan 1 00:00:17 1996
  1058. Subject: Utilizing expanded memory
  1059.  
  1060. 17. *****
  1061.  Q: How can I utilize expanded memory (EMS) in my programs?
  1062.  
  1063.  A: I have no experience (yet?) on this subject myself, but I can
  1064. give you a list of references: Michael Tischer (1990), Turbo Pascal
  1065. Internals, Abacus, Chapter 9; Michael Tischer (1992), PC Intern
  1066. System Programming, Chapter 12; Stephen O'Brien (1988), Turbo
  1067. Pascal, Advanced Programmer's Guide, Borland-Osborne, Chapter 4;
  1068. Chris Ohlsen & Gary Stoker (1989), Turbo Pascal Advanced Techniques,
  1069. Que, Chapter 11, Robert Jourdain (1992), Programmer's Problem
  1070. Solver, 2nd ed., Brady Publishing, pp. 68-87, and, maybe most
  1071. importantly, Dorfman & Neuberger, Turbo Pascal Memory Management
  1072. Techniques (with lots of code).
  1073.    Furthermore, Turbo Pascal delivery disks (at least 5.0) contain a
  1074. demos.arc archive which includes an ems.pas file.
  1075. --------------------------------------------------------------------
  1076.  
  1077. From ts@uwasa.fi Mon Jan 1 00:00:18 1996
  1078. Subject: Capturing the entire command line
  1079.  
  1080. 18. *****
  1081.  Q: How can I obtain the entire command line (spaces and all)?
  1082.  
  1083.  A: ParamCount and ParamStr are for parsed parts of the command line
  1084. and cannot be used to get the command line exactly as it was. See
  1085. what happens if you try to capture
  1086.   "Hello.   I'm here"
  1087. you'll end up with a false number of blanks. For obtaining the
  1088. command line unaltered use
  1089.   type CommandLineType = string[127];
  1090.   var  CommandLinePtr  : ^CommandLineType;
  1091.   begin
  1092.     CommandLinePtr := Ptr(PrefixSeg, $80);
  1093.     writeln (CommandLinePtr^);
  1094.   end;
  1095. A warning. If you want to get this correct (the same goes for TP's
  1096. own ParamStr and ParamCount) apply them early in your program. At
  1097. least they must be used before any disk I/O takes place!
  1098. :
  1099. A related example demonstrating a function giving the number of
  1100. characters on the command line
  1101.   function CMDNBRFN : byte;
  1102.   var paramPtr : ^byte;
  1103.   begin
  1104.     paramPtr := Ptr (PrefixSeg, $80);
  1105.     cmdnbrfn := paramPtr^
  1106.   end;  (* cmdnbrfn *)
  1107. For the contents of the Program Segment Prefix (PSP) see Tischer,
  1108. Michael (1992), PC Intern System Programming, p. 753.
  1109. --------------------------------------------------------------------
  1110.  
  1111. From ts@uwasa.fi Mon Jan 1 00:00:19 1996
  1112. Subject: Redirecting from printer to file
  1113.  
  1114. 19. *****
  1115.  Q: How do I redirect text from printer to file in my TP program?
  1116.  
  1117.  A: Simple. This is done in Turbo Pascal by using the assign command
  1118. (think what the word 'assign' implies). Here is a simple example of
  1119. the idea.
  1120.   uses Printer;
  1121.   begin
  1122.     assign (lst, 'printer.log');
  1123.     rewrite (lst);
  1124.     writeln (lst, 'Hello world');
  1125.     close (lst);
  1126.   end.
  1127. --------------------------------------------------------------------
  1128.  
  1129. From ts@uwasa.fi Mon Jan 1 00:00:20 1996
  1130. Subject: Turbo Pascal users are just wimps
  1131.  
  1132. 20. *****
  1133.  Q: Turbo Pascal is for wimps. Why don't you use standard Pascal or
  1134. better still why don't you use C?
  1135.  
  1136.  A: These kinds of "real-programmers" statements often reflect what
  1137. is called self-over-others attitude, and they are a part of a kind
  1138. of a programming lore or cult. Basically, these attitudes waive the
  1139. simple fact that one should select one's tools according to the task
  1140. at hand, not vice versa. On the other hand one's productivity is
  1141. usually best when being able to use tools which one is familiar and
  1142. comfortable with. (Note however that the real-programmer's lore is
  1143. not really interested in producing results.)
  1144.    In very rough terms there are two attitudes to programming
  1145. languages. They can be seen as tools for writing applications, or
  1146. (by surprisingly many) as ends themselves.
  1147.    If we first look at standard Pascal (versus Turbo Pascal),
  1148. considering the language primary and its usage secondary is common.
  1149. This results from the history of Pascal, since as we all know it was
  1150. originally meant as a means for teaching programming concepts, not
  1151. at all for writing applications. But because Pascal turned out to be
  1152. useful also for writing applications, it has been extended for some
  1153. operating systems, most notably MS-DOS (Turbo Pascal) and VAX/VMS
  1154. (VAX Pascal). Both remedy a lot of flaws from the application
  1155. programmer's point of view. Most importantly they have a true file
  1156. I/O interface, and enhanced string handling. Turbo Pascal (the more
  1157. generic of these two) clearly draws from the structure and ideas of
  1158. advanced BASICs (and vice versa). While in standard Pascal the
  1159. language is an end by itself, for Turbo Pascal the only relevant
  1160. issue is its usefulness for writing applications.
  1161.    One problem that one encounters when moving away from standard
  1162. Pascal is the problem of portability. This is a truly serious
  1163. problem, since most often extensive rewriting is necessary from
  1164. converting say Turbo Pascal to, say, Unix Pascal. I have taken Unix
  1165. Pascal as the extreme example, since Unix Pascal is almost nothing
  1166. but the standard Pascal having no useful file I/O.
  1167.    If one considers C, its best aspect from applications point of
  1168. view is portability, and its strength for system programming. But it
  1169. is not an easy language to learn. Proponents of C also often have
  1170. the tendency discussed above, that is seeing the language as
  1171. primary, and its utilization as secondary. Now why this tendency,
  1172. not only for C, but in general? I've had the opportunity of writing
  1173. programs starting from the late 1960's, and one observation I have
  1174. made, and often propounded the view is that it is not writing code
  1175. that is the really difficult part. What is really difficult it is
  1176. coming up with good and original ideas for programs to write. I see
  1177. applications as primary, and the tools as secondary. As to Turbo
  1178. Pascal, I've written in many languages (including Cobol, Fortran,
  1179. several Basics and Pascals, and command languages) and I like Turbo
  1180. Pascal because it is one of the most convenient and flexible tools
  1181. for writing the kind of applications that I usually write and
  1182. distribute for the Public Domain. That is I use Turbo Pascal because
  1183. I'm comfortable with it in writing applications, and have thus
  1184. gathered a very useful modular library for it over the years, not
  1185. because of any inherent value attached to Turbo Pascal per se.
  1186.  
  1187.  A2: Another, a somewhat resembling line is made up by the arguments
  1188. about standards in Pascal which were recycled in the late
  1189. comp.lang.pascal time after time. Very often they end up with
  1190. purists vs pragmatists arguing about the true or imaginary viles of
  1191. using GOTOs. I find all this somewhat futile, although I understand
  1192. the academic nature of the background. As you'll recall, Pascal was
  1193. first developed for academic teaching programming concepts, not for
  1194. any practical programming. That came later, and the ensuing
  1195. popularity of Pascal in practical applications must have come as a
  1196. surprise way back then. I admit being biased in not sympathizing
  1197. with Pascal standard stalwarts. I am far more interested in getting
  1198. the job done than in defending a barren orthodoxy.
  1199.    Since Turbo Pascal version 7.0 introduced the "break" and
  1200. "continue" keywords to handle jumps in loops, GOTOs are much easier
  1201. to avoid without undue complications.
  1202. --------------------------------------------------------------------
  1203.  
  1204. From ts@uwasa.fi Mon Jan 1 00:00:21 1996
  1205. Subject: Turning off the cursor
  1206.  
  1207. 21. *****
  1208.  Q: How do I turn the cursor off?
  1209.  
  1210.  A: The usually advocated trick for turning the cursor off is to
  1211. equate the lower and the upper scan line of the cursor as explained
  1212. e.g. in Stephen O'Brien (1988), Turbo Pascal, Advanced Programmer's
  1213. Guide.
  1214.      uses Dos;
  1215.      var regs : registers;
  1216.      begin
  1217.        regs.ax := $0100;   (* Service $01 *)
  1218.        regs.cl := $20;     (* Top scan line *)
  1219.        regs.ch := $20;     (* Bottom scan line *)
  1220.        Intr ($10, regs);   (* ROM BIOS video driver interrupt *)
  1221.      end;
  1222. To turn the cursor back on this (and many other) sources suggest
  1223. setting regs.ch and regs.cl as 12 and 13 for mono screen, and 6 and
  1224. 7 for others.
  1225.    This is not a good solution since it is equipment dependent, and
  1226. may thus produce unexpected results. Better to store the current
  1227. scan line settings, and turn off the cursor bit. Below is the code
  1228. from ftp://garbo.uwasa.fi/pc/ts/tspa3470.zip (or whatever version
  1229. number is the latest) available by anonymous FTP from garbo.uwasa.fi
  1230. archives. The general idea is that regs.ch bit 5 toggles the cursor
  1231. on / off state. Thus to set the cursor off, apply
  1232.   regs.ch := regs.ch or $20;    (* $20 = 00100000 *)
  1233. and to set it on, apply
  1234.   regs.ch := regs.ch and $DF;   (* $DF = 11011111 *)
  1235. (* From TSUNTE unit, which also has a CURSON procedure *)
  1236. procedure CURSOFF;
  1237. var regs : registers;
  1238. begin
  1239.   FillChar (regs, SizeOf(regs), 0);  (* Initialize, a precaution *)
  1240.   {... find out the current cursor size (regs.ch, regs.cl) ...}
  1241.   regs.ah := $03;
  1242.   regs.bh := $00;    (* page 1, superfluous because of FillChar *)
  1243.   Intr ($10, regs);  (* ROM BIOS video driver interrupt *)
  1244.   {... turn off the cursor without changing its size ...}
  1245.   regs.ah := $01;                   (* Below are bits 76543210 *)
  1246.   regs.ch := regs.ch or $20;  (* Turn on bit 5; $20 = 00100000 *)
  1247.   Intr ($10, regs);
  1248. end;  (* cursoff *)
  1249.  
  1250.  A2: A comment from Leonard Erickson leonard@qiclab.scn.rain.com.
  1251. Reprinted with permission. There's a *reason* those sources don't
  1252. suggest storing the current scan line settings. On IBM Monochrome
  1253. Display Adapters (MDA), Hercules Graphics Cards, and the various
  1254. clones of both, the "read cursor start and end scan lines" function
  1255. *always* returns the same values. And those values are almost never
  1256. the actual settings. Most cards return 6 & 7. Some return 12 & 13.
  1257. But they return these values even if the cursor has been set to
  1258. something else.
  1259.    So you are *still* stuck with checking the hardware type if the
  1260. screen is in mode 7.
  1261.    See the Interrupt list for details on this mess.
  1262.  
  1263.  A3: Another solution that has been suggested is putting the cursor
  1264. outside the screen.  But you can't do this with the Crt's GotoXY
  1265. procedure, since it ignores off screen positions, as observed by
  1266. Luiz Marques luiz.marques%mandic@ibase.org.br. You'll need to use
  1267. video interrupt, that is $10, function $02. Fair enough, but
  1268. somewhat complicated. Besides, how do you write on the screen if the
  1269. cursor position is off it?
  1270.  
  1271.  A4: This snippet of disabling the cursor at hardware level was
  1272. posted to comp.lang.pascal (now news:comp.lang.pascal.borland) by
  1273. JAB@ib.rl.ac.uk. Corrections due to John Stockton. John also points
  1274. out that this probably needs a VGA to work.
  1275.   procedure turn_off_cursor;
  1276.   var num : word;
  1277.   begin
  1278.     port[$03D4]:=$0A; num:=port[$03D5];
  1279.     port[$03D4]:=$0A; port[$03D5]:=num or 32;
  1280.   end;
  1281.   {}
  1282.   procedure turn_on_cursor;
  1283.   var num : word;
  1284.   begin
  1285.     port[$03D4]:=$0A; num:=port[$03D5];
  1286.     port[$03D4]:=$0A; port[$03D5]:=num and not 32;
  1287.   end;
  1288.   {}
  1289.   procedure toggle_cursor;
  1290.   var num : word;
  1291.   begin
  1292.     port[$03D4]:=$0A; num:=port[$03D5];
  1293.     port[$03D4]:=$0A; port[$03D5]:=num xor 32;
  1294.   end;
  1295.  
  1296.  A5: (Not to be taken seriously). Simple, turn off your computer and
  1297. the cursor stops showing :-).
  1298. --------------------------------------------------------------------
  1299.  
  1300. From ts@uwasa.fi Mon Jan 1 00:00:22 1996
  1301. Subject: Finding the roots of a polynomial
  1302.  
  1303. 22. *****
  1304.  Q: How to find all roots of a polynomial?
  1305.  
  1306.  A: If you need the code, see Turbo Pascal Numerical Toolbox and/or
  1307. Press & Flannery & Teukolsky & Vetterling (1986), Numerical Recipes,
  1308. The Art of Scientific Computing, Cambridge University Press. The
  1309. Numerical Recipes codes are available as /pc/turbopas/nrpas13.zip
  1310. (big, 404k!). If you just need to solve such a task (without code
  1311. available), get ftp://garbo.uwasa.fi/pc/ts/tsnum12.zip (or whatever
  1312. version number is the latest) from garbo.uwasa.fi archives by
  1313. anonymous FTP or mail server.
  1314. --------------------------------------------------------------------
  1315.  
  1316. From ts@uwasa.fi Mon Jan 1 00:00:23 1996
  1317. Subject: Pascal homework on the net
  1318.  
  1319. 23. *****
  1320.  Q: What is all this talk about "Pascal homework on the net"?
  1321.  
  1322.  A: This is one of the subjects that seems to pop up at regular
  1323. intervals, cause some heated exchange for awhile, and then die down
  1324. again leaving some users harboring warranted or unwarranted grudges.
  1325.    Some posters to comp.lang.pascal (later comp.lang.pascal.borland)
  1326. have been very concerned of the possibility that the questions posed
  1327. on the net are related to students' homework assignments. I don't
  1328. have any unequivocal answers or a clear-cut stand on this question,
  1329. just some comments.
  1330.    The most important task of a newsgroup like comp.lang.pascal.borland
  1331. is the exchange of information between the users. If you think that
  1332. what you are going to post is interesting and useful to the group,
  1333. that should be your topmost criterion.
  1334.    If it is really a student that wants his/her work done on the net
  1335. (how do we know anyway?) also consider the following fact. Being
  1336. able to use a newsgroup amounts to having learned at least something
  1337. about using computers, and that is something per se.
  1338.    Even if the student may short-sightedly not realize it, providing
  1339. ALL the code for a student's homework is detrimental to the student,
  1340. since it is she/he that foregoes understanding what he/she is doing.
  1341. The group should not condone outright cheating. Being (partly) a
  1342. teacher myself, I understand also this view.
  1343.    If a student is stuck with a problem in his/her code, I don't see
  1344. any real harm in helping out, especially if the problem has general
  1345. interest. Instructing is what teaching is about, anyway, isn't it?
  1346.    But, on the other hand, I must admit that I find a it rather
  1347. flagrant if a posting asks for something of the kind "I have to
  1348. complete my term assignment to write a function plotter by the end
  1349. of this month. Send me the code, since I'm too busy with my other
  1350. exams to write it myself" (a true quote).
  1351.    Finally, let's not jump to premature conclusions about anyone's
  1352. questions.  That's what most often triggers off a vicious circle of
  1353. flaming.
  1354. --------------------------------------------------------------------
  1355.  
  1356. From ts@uwasa.fi Mon Jan 1 00:00:24 1996
  1357. Subject: Linking bgi drivers into executables
  1358.  
  1359. 24. *****
  1360.  Q: How can I link graphics drivers directly into my executable?
  1361.  
  1362.  A: This is a complicated, yet a very useful task, because then you
  1363. won't need any separate graphics drivers (or fonts) to go separately
  1364. along with your program. Unfortunately, Turbo Pascal documentation
  1365. on this task is a bit confusing.
  1366.    1) The very first step is to get the necessary files from the
  1367. Turbo Pascal disks to your working directory. To start with, you'll
  1368. need binobj.exe and all the .bgi files.
  1369.    2) Run the following commands (best to place them in a batch,
  1370. call it e.g. makeobj.bat):
  1371.      binobj cga.bgi cga CGADriverProc
  1372.      binobj egavga.bgi egavga EGAVGADriverProc
  1373.      binobj herc.bgi herc HercDriverProc
  1374.      binobj pc3270.bgi pc3270 PC3270DriverProc
  1375.      binobj att.bgi att ATTDriverProc
  1376.      rem binobj ibm8514.bgi 8514 IBM8514DriverProc
  1377.    3) Get drivers.pas from the Turbo Pascal disk and compile it with
  1378. Turbo Pascal. Now you have a drivers.tpu unit which contains all the
  1379. graphics drivers.
  1380.    4) Now you won't need the .bgi and the .obj files any more. You
  1381. may delete them from your working directory.
  1382.    5) Write your graphics program in the usual manner. But before
  1383. putting your program in the graphics mode use the following
  1384. procedure if you want to link e.g. the EGAVGA graphics driver
  1385. directly into your executable. (Link just the driver(s) you'll need,
  1386. since the drivers take up a lot of space.)
  1387.      uses Graph, Drivers;
  1388.      :
  1389.      procedure EGAVGA2EXE;
  1390.      begin
  1391.        if RegisterBGIdriver(@EGAVGADriverProc) < 0 then
  1392.          begin
  1393.            writeln ('EGA/VGA: ', GraphErrorMsg(GraphResult));
  1394.            halt(1);
  1395.          end;
  1396.      end; (* egavga2exe *)
  1397.      :
  1398.    Linking the .bgi and .chr drivers is also covered in Swan (1989),
  1399. Mastering Turbo Pascal 5.5 pp. 355-359 and Mitchell (1993), Borland
  1400. Pascal Developer's Guide , pp. 221-229.
  1401.    If you have Turbo Pascal 7.0 its help function gives you an
  1402. example code. One way of getting at it is the following. In the
  1403. Turbo Pascal IDE (that is in the editor) type RegisterBGIdriver.
  1404. Then place the cursor on it and press alt-F1 for help of that
  1405. keyword. Press alt-F10 and select "Copy example". Press first <ESC>
  1406. then alt-F10 and select Paste. The example code is pasted within
  1407. your program for you to study.
  1408.    Incidentally, although this is a slightly different matter, you
  1409. can link any data material into your executable. See Stephen
  1410. O'Brien, (1988), Turbo Pascal, Advanced Programmer's Guide, pp. 31 -
  1411. 35 for more details.
  1412. --------------------------------------------------------------------
  1413.  
  1414. From ts@uwasa.fi Mon Jan 1 00:00:25 1996
  1415. Subject: Trapping runtime errors
  1416.  
  1417. 25. *****
  1418.  Q: How can I trap a runtime error?
  1419.  
  1420.  A: What you are probably asking for is a method writing a program
  1421. termination routine of your own. To do this, you have to replace
  1422. Turbo Pascal's ExitProc with your own customized exec procedure.
  1423. Several Turbo Pascal text books show ho to do this. See e.g. Tom
  1424. Swan (1989), Mastering Turbo Pascal 5.5, Third edition, Hayden
  1425. Books, pp. 440-454; Michael Yester (1989), Using Turbo Pascal, Que,
  1426. pp. 376-382; Stephen O'Brien (1988), Turbo Pascal, Advanced
  1427. Programmer's Guide, pp. 28-30; Tom Rugg & Phil Feldman (1989), Turbo
  1428. Pascal Programmer's Toolkit, Que, pp. 510-515. Here is an example
  1429.   var OldExitProcAddress : Pointer;
  1430.       x : real;
  1431.   {$F+} procedure MyExitProcedure; {$F-}
  1432.   begin
  1433.     if ErrorAddr <> nil then
  1434.       begin
  1435.         writeln ('Runtime error number ', ExitCode, ' has occurred');
  1436.         writeln ('The error address in decimal is ',
  1437.                   Seg(ErrorAddr^):5,':',Ofs(ErrorAddr^):5);
  1438.         writeln ('That''s all folks, bye bye');
  1439.         ErrorAddr := nil;
  1440.         ExitCode  := 0;
  1441.       end;
  1442.     {... Restore the pointer to the original exit procedure ...}
  1443.     ExitProc := OldExitProcAddress;
  1444.   end;  (* MyExitProcedure *)
  1445.   (* Main *)
  1446.   begin
  1447.     OldExitProcAddress := ExitProc;
  1448.     ExitProc := @MyExitProcedure;
  1449.     x := 7.0; writeln (1.0/x);
  1450.     x := 0.0; writeln (1.0/x);   {The trap}
  1451.     x := 7.0; writeln (4.0/x);   {We won't get this far}
  1452.   end.
  1453. :
  1454. Actually, I utilize this idea in my /pc/ts/tspa3470.zip Turbo Pascal
  1455. units collection, which includes a TSERR.TPU. If you put TSERR in
  1456. your program's uses statement, all the run time errors will be given
  1457. verbally besides the usual, cryptic error number. That's all there
  1458. is to it. That is, the inclusion to the uses statement to your main
  1459. program (if you have the program in several units) is all you have
  1460. to do to enable this handy feature.
  1461. :
  1462. Hans.Siemons@f149.n512.z2.fidonet.org notes "This line:
  1463.     ExitProc := OldExitProcAddress;
  1464. should IMHO never be placed at the end of your exit handler. If for
  1465. one reason or another your own handler should cause a runtime error,
  1466. it would go in an endless loop. If the first statement restores the
  1467. exit chain, this can never happen. I do agree that is not very
  1468. likely that your exit handler produces any runtime error, but it
  1469. performs I/O, and since it is located in a FAQ, people are bound to
  1470. use, and maybe extend it with more tricky stuff."
  1471. --------------------------------------------------------------------
  1472.  
  1473. From ts@uwasa.fi Mon Jan 1 00:00:26 1996
  1474. Subject: Using ansi codes in a TP program
  1475.  
  1476. 26. *****
  1477.  Q: How to get ansi control codes working in Turbo Pascal writes?
  1478.  
  1479.  A: It is very simple, but one has to be aware of the pitfalls.
  1480. Let's start from the assumption that ansi.sys or a corresponding
  1481. driver has been loaded, and that you know ansi codes. If you don't,
  1482. you'll find that information in the standard MS-DOS manual. To apply
  1483. ansi codes you just include the ansi codes in your write statements.
  1484. For example the following first clears the screen and then puts the
  1485. text at location 10,10:
  1486.    write (#27, '[2J');         (* the ascii code for ESC is 27 *)
  1487.    write (#27, '[10;10HUsing ansi codes can be fun');
  1488. If you want to test (as you should) whether ansi.sys or some some
  1489. replacement driver has been loaded, you can use the ISANSIFN
  1490. function from my ftp://garbo.uwasa.fi/pc/ts/tspa3470.zip.
  1491. Now the catches. If you have a
  1492.    uses Crt;
  1493. statement in your program, direct screen writes will be used, and
  1494. the ansi codes won't work. You have either to leave out the Crt
  1495. unit, or include
  1496.    assign (output, '');
  1497.    rewrite (output);
  1498.    :
  1499.    close (output);
  1500. Occasionally I have seen it suggested that one should just set
  1501.    DirectVideo := false;
  1502. This is a popular misconception. It won't produce the desired
  1503. result. I'm not claiming to know the reason for this quirk of Turbo
  1504. Pascal. Rather it is an observation I've made.
  1505.  
  1506. -From: Bengt Oehman d92bo@efd.lth.se with a later dicussion with Bob
  1507. Peck bpeck@prairienet.org and help from Duncan Murdoch
  1508. dmurdoch@mast.queensu.ca. The `DirectVideo:=False' statement only
  1509. tells the Crt unit to use BIOS calls instead of using direct
  1510. video-memory writes. A demo program to illustrate the screen writing
  1511. modes follows:
  1512.  
  1513. Program ScreenWriteDemo;
  1514. USES Crt;
  1515. BEGIN
  1516.   Writeln('This is written directly to the video memory');
  1517.   DirectVideo:=False;
  1518.   Writeln('This is written via BIOS interrupt calls (int 10h)');
  1519.   Assign(Output,'');
  1520.   Append(Output);
  1521.   Writeln('This is written via DOS calls (int 21h)');
  1522. END.
  1523.  
  1524. A note: The latter could be also written as
  1525.   Writeln(Output, 'This is written via DOS calls (int 21h)');
  1526. since the writeln default is the standard output.
  1527. --------------------------------------------------------------------
  1528.  
  1529. From ts@uwasa.fi Mon Jan 1 00:00:27 1996
  1530. Subject: Writing an expression parser
  1531.  
  1532. 27. *****
  1533.  Q: How to evaluate a function given as a string to the program?
  1534.  
  1535.  A: To do this you have to have a routine for parsing and evaluating
  1536. your expression. This is a complicated task requiring a clever use
  1537. of recursion. You can find such code in Stephen O'Brien (1988),
  1538. Turbo Pascal, The Complete Reference. Borland-Osborne/McGraw-Hill,
  1539. Chapter 10. Another, simpler piece of code can be found in Michael
  1540. Yester (1989), Using Turbo Pascal, Que, Chapter 5.
  1541.    I've also written such a function evaluation program myself, and
  1542. much of it is based on the ideas in O'Brien with my own corrections
  1543. and enhancements. The resulting program is available as fn.exe
  1544. function evaluator in the ftp://garbo.uwasa.fi/pc/ts/tsfunc13.zip
  1545. package (or whatever version number is the latest). Note however,
  1546. that the source code is not included, nor available.
  1547.    Tips from Justin Lee (ossm1jl@rex.uokhsc.edu):
  1548.  67666 Sep 22 03:00 ftp://garbo.uwasa.fi/pc/turboobj/parstp30.zip
  1549.  parstp30.zip Recursive expression TP7.0/BP/VB/C++ parser, R.Loewy
  1550. An excellent parser is included with all the Turbo Pascal versions
  1551. since TP4.0 as part of the MCALC or TCALC spreadsheet example
  1552. program. See mcparse.pas or tcparse.pas.
  1553. --------------------------------------------------------------------
  1554.  
  1555. From ts@uwasa.fi Mon Jan 1 00:00:28 1996
  1556. Subject: Detecting redirection
  1557.  
  1558. 28. *****
  1559.  Q: How does one detect whether input (or output) is redirected?
  1560.  
  1561.  A: As we know input to a program can come from a file, from the
  1562. console, or from a pipe or redirection. Examples of the latter are
  1563.      type text.dat | program
  1564.      program < text.dat
  1565. A Turbo Pascal program can be made to detect the redirections using
  1566. Interrupt 21Hex, function 44Hex, subfunction 00Hex. See PC Magazine
  1567. April 16, 1991, p. 374 for the code, and Duncan (1988), Advanced
  1568. MS-DOS Programming, pp. 412-413 for more information. Alternatively,
  1569. you can utilize the preprogrammed routines
  1570.   PIPEDIFN Is the standard input from redirection
  1571.   PIPEDNFN Is the standard output redirected to nul
  1572.   PIPEDOFN Is the standard output redirected
  1573. from my ftp://garbo.uwasa.fi/pc/ts/tspa3470.zip units.
  1574. --------------------------------------------------------------------
  1575.  
  1576. From ts@uwasa.fi Mon Jan 1 00:00:29 1996
  1577. Subject: Setting the 43/50 line text mode
  1578.  
  1579. 29. *****
  1580.  Q: How does one set the 43/50 line text mode?
  1581.  
  1582.  A: Quite simple. Just apply TextMode (C80 + font8x8).  Requires a
  1583. "uses Crt;". First, however, you should test that you have a at
  1584. least an EGA video adapter. (See DetectGraph in your TP manual).
  1585. Also see TSUTLE.NWS in ftp://garbo.uwasa.fi/pc/ts/tsutle22.zip (or
  1586. whichever version number is the current) for the non-standard wide
  1587. text modes like 132x43.
  1588.   { An example }
  1589.   uses Crt;
  1590.   var InitialMode : integer;
  1591.   begin
  1592.     InitialMode := LastMode;
  1593.     TextMode (CO80 + Font8x8);
  1594.     TextColor (LightCyan);
  1595.     writeln ('Test1');
  1596.     readln;
  1597.     {}
  1598.     TextMode (CO40);
  1599.     writeln ('Test2');
  1600.     readln;
  1601.     {}
  1602.     TextMode (InitialMode);
  1603.     TextColor (Yellow);
  1604.     writeln ('Test3');
  1605.     readln;
  1606.   end.
  1607. --------------------------------------------------------------------
  1608.  
  1609. From ts@uwasa.fi Mon Jan 1 00:00:30 1996
  1610. Subject: Assigning environment variable values
  1611.  
  1612. 30. *****
  1613.  Q: How can I assign a value to an environment variable in TP?
  1614.  
  1615.  A: For assigning a value to (a parent process's) environment value
  1616. you have to access and manipulate the Program Segment Prefix and
  1617. Memory Control Blocks. This is a rather complicated undertaking. A
  1618. source code with an accompanying article by Trudy Neuhaus can be
  1619. found in PC Magazine Volume 11 Number 1 pages 425-427.
  1620.    The budding TP programmers should note that the elementary trick
  1621. of Exec (GetEnv('comspec'), '/c set key=whatever') will achieve only
  1622. a transient result for the duration of the exec shell. When you exit
  1623. the shell after this endeavor, the environment will be as it was.
  1624.    Here is about the why. When the above command is executed, MS-DOS
  1625. makes a copy of the environment, and uses the copy. When the above
  1626. shelling terminates, the copy of the environment is deleted, and the
  1627. original is restored. Hence the above trick cannot be used to change
  1628. the parent environment.
  1629.    If you don't want to try to go through this rather complicated
  1630. task yourself, the routines
  1631.  "SETEVN   Set a parent environment variable (variable=value)"
  1632.  "SETENVSH Set an environment variable for the duration of shelling"
  1633. can be found in my TP TPU collection ftp://garbo.uwasa.fi/pc/ts/
  1634. tspa34*.zip (* = 40,50,55,60,70). No source code is included, nor
  1635. available for tspa34. However, there is a TPENV section within
  1636. ftp://garbo.uwasa.fi/pc/turbopas/bonus507.zip. From zeta@tcscs.com
  1637. Gregory Youngblood: For a source code see /pc/source/setenv.zoo at
  1638. Garbo.
  1639.    One further detail. Users sometimes ask how one can change the
  1640. prompt or the path from within a Turbo Pascal program. This is in no
  1641. way different from changing the value of any other environment
  1642. variable. Both PATH and PROMPT are environment variables that can be
  1643. set with the MS-DOS SET command in the fashion described in the
  1644. above. This is not changed in any way by the fact that you can apply
  1645. PROMPT and PATH also in an alternative format not requiring the SET
  1646. command.
  1647. --------------------------------------------------------------------
  1648.